﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace YonYou.U8.IN.Model
{
	public abstract class BizNode<T> : IEnumerable<BizNode<T>>, IEnumerable, ICloneable where T : new()
	{
		public BizNode()
		{
		}

		public BizNode(T data) : this()
		{
			this.Data = data;
			this.Childs = new BizNodeCollection<T>();
		}

		public BizNode(T data, BizNode<T> children) : this(data)
		{
			this.PutCache(children);
			this.Childs.Add(children);
		}

		public BizNode(T data, BizNodeCollection<T> childs) : this(data)
		{
			if (childs != null)
			{
				foreach (BizNode<T> bizNode in childs)
				{
					this.PutCache(bizNode);
					this.Childs.Add(bizNode);
				}
			}
		}

		public BizNode(T data, BizNode<T>[] childs) : this(data)
		{
			if (childs != null)
			{
				foreach (BizNode<T> bizNode in childs)
				{
					this.PutCache(bizNode);
					this.Childs.Add(bizNode);
				}
			}
		}

		public BizNode(T data, IEnumerable<BizNode<T>> childs) : this(data)
		{
			if (childs != null)
			{
				foreach (BizNode<T> bizNode in childs)
				{
					this.PutCache(bizNode);
					this.Childs.Add(bizNode);
				}
			}
		}

		public BizNode<T> Parent { get; internal set; }

		public BizNodeCollection<T> Childs { get; private set; }

		public T Data { get; internal set; }

		public object Tag { get; set; }

		internal static BizNodeCache<T> NodeCache
		{
			get
			{
				return BizNode<T>.m_NodeCache;
			}
		}

		public virtual void Append(BizNode<T> child)
		{
			if (child == null)
			{
				return;
			}
			if (child.Parent == null)
			{
				child.Parent = this;
				this.PutCache(child);
				this.Childs.Add(child);
				return;
			}
			throw new InvalidOperationException();
		}

		public virtual void Append(BizNodeCollection<T> childs)
		{
			if (childs == null)
			{
				return;
			}
			foreach (BizNode<T> bizNode in childs)
			{
				if (bizNode.Parent != null)
				{
					throw new InvalidOperationException();
				}
				bizNode.Parent = this;
				this.PutCache(bizNode);
				this.Childs.Add(bizNode);
			}
		}

		public virtual void Append(params BizNode<T>[] childs)
		{
			if (childs == null)
			{
				return;
			}
			foreach (BizNode<T> bizNode in childs)
			{
				this.PutCache(bizNode);
				this.Append(bizNode);
			}
		}

		internal void Append(IEnumerable<BizNode<T>> childs)
		{
			if (childs == null)
			{
				return;
			}
			foreach (BizNode<T> bizNode in childs)
			{
				this.PutCache(bizNode);
				this.Append(bizNode);
			}
		}

		public virtual BizNode<T> RemoveChild(BizNode<T> oldChild)
		{
			if (oldChild == null)
			{
				return null;
			}
			if (oldChild.Parent != this)
			{
				throw new InvalidOperationException();
			}
			this.RemoveFromCache(oldChild);
			this.Childs.Remove(oldChild);
			oldChild.Parent = null;
			return oldChild;
		}

		public virtual void Remove()
		{
			if (this.Parent == null)
			{
				throw new InvalidOperationException();
			}
			this.RemoveFromCache(this);
			this.Parent.RemoveChild(this);
		}

		public virtual void RemoveAllChild()
		{
			if (this.Childs.Count == 0)
			{
				return;
			}
			for (int i = 0; i < this.Childs.Count; i++)
			{
				this.RemoveFromCache(this.Childs[i]);
				this.RemoveChild(this.Childs[i]);
			}
		}

		protected abstract void PutCache(BizNode<T> node);

		protected abstract void RemoveFromCache(BizNode<T> node);

		public object Clone()
		{
			return this.CloneElement(true);
		}

		public virtual BizNode<T> CloneElement(bool deep)
		{
			throw new NotImplementedException();
		}

		internal virtual Q CloneImp<Q>(bool deep) where Q : BizNode<T>, new()
		{
			Q result = Activator.CreateInstance<Q>();
			result.CopyAttribute(this);
			if (deep)
			{
				result.CopyChilden(this, deep);
			}
			return result;
		}

		internal void CopyChilden(BizNode<T> container, bool deep)
		{
			foreach (BizNode<T> bizNode in container.Childs)
			{
				this.Append(new BizNode<T>[]
				{
					bizNode.CloneElement(deep)
				});
			}
		}

		internal void CopyAttribute(BizNode<T> container)
		{
			this.Tag = container.Tag;
			this.Data = container.Data;
		}

		public IEnumerator GetEnumerator()
		{
			return this.Childs.GetEnumerator();
		}

		IEnumerator<BizNode<T>> IEnumerable<BizNode<T>>.GetEnumerator()
		{
			return this.Childs.GetEnumerator();
		}

		private static BizNodeCache<T> m_NodeCache = new BizNodeCache<T>();
	}
}